﻿namespace Microsoft.VisualStudio.BaseCustomTool
{
    using System;
    using System.Runtime.InteropServices;

    internal class ServiceProvider : IServiceProvider, IObjectWithSite
    {
        private static Guid IID_IUnknown = new Guid("{00000000-0000-0000-C000-000000000046}");
        private IOleServiceProvider serviceProvider;

        public ServiceProvider(IOleServiceProvider sp)
        {
            this.serviceProvider = sp;
        }

        public virtual void Dispose()
        {
            if (this.serviceProvider != null)
            {
                this.serviceProvider = null;
            }
        }

        public static bool Failed(int hr)
        {
            return (hr < 0);
        }

        public virtual object GetService(Guid serviceClass)
        {
            return this.GetServiceInternal(serviceClass);
        }

        public virtual object GetService(Type serviceClass)
        {
            if (serviceClass == null)
            {
                return null;
            }
            return this.GetServiceInternal(serviceClass.GUID);
        }

        private object GetServiceInternal(Guid guid)
        {
            IntPtr ptr;
            if (this.serviceProvider == null)
            {
                return null;
            }
            object objectForIUnknown = null;
            if (guid.Equals(Guid.Empty))
            {
                return null;
            }
            if (guid.Equals(typeof(IOleServiceProvider).GUID))
            {
                return this.serviceProvider;
            }
            if (guid.Equals(typeof(IObjectWithSite).GUID))
            {
                return this;
            }
            if (Succeeded(this.serviceProvider.QueryService(ref guid, ref IID_IUnknown, out ptr)) && (ptr != IntPtr.Zero))
            {
                objectForIUnknown = Marshal.GetObjectForIUnknown(ptr);
                Marshal.Release(ptr);
            }
            return objectForIUnknown;
        }

        void IObjectWithSite.GetSite(ref Guid riid, object[] ppvSite)
        {
            ppvSite[0] = this.GetService(riid);
        }

        void IObjectWithSite.SetSite(object pUnkSite)
        {
            IOleServiceProvider sp = pUnkSite as IOleServiceProvider;
            if (sp != null)
            {
                this.serviceProvider = sp;
            }
        }

        public static bool Succeeded(int hr)
        {
            return (hr >= 0);
        }
    }
}

